package com.yanqu.road.server.gameplayer.module.thief;

import com.yanqu.road.entity.config.thief.ThiefInfo;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.log.LogThiefReward;
import com.yanqu.road.entity.player.UserBuilding;
import com.yanqu.road.entity.player.UserThief;
import com.yanqu.road.logic.bussiness.config.ThiefBusiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.ThiefPb;
import com.yanqu.road.pb.thief.ThiefProto;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.base.GeneralModule;
import com.yanqu.road.server.gameplayer.module.player.AttributeModule;
import com.yanqu.road.server.gameplayer.module.player.BuildingModule;
import com.yanqu.road.server.gameplayer.module.player.CurrencyModule;
import com.yanqu.road.server.manger.config.SystemOpenMgr;
import com.yanqu.road.server.manger.config.ThiefMgr;
import com.yanqu.road.server.manger.log.LogMgr;
import com.yanqu.road.server.manger.system.SystemSwitchMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.LocalDateTimeHelper;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.UUIDHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class ThiefModule extends GeneralModule {

    private Map<String, UserThief> thiefMap = new ConcurrentHashMap<>();

    private final Object createLock = new Object();

    public ThiefModule(GamePlayer player) {
        super(player);
    }

    @Override
    public boolean loadData() {
        thiefMap = ThiefBusiness.getUserThiefMap(player.getUserId());
        return true;
    }

    @Override
    public boolean afterLoadData() {
        return true;
    }

    @Override
    public boolean saveData() {
        for (UserThief userThief : thiefMap.values()) {
            if (userThief.isInsertOption()) {
                ThiefBusiness.addUserThief(userThief);
            } else if (userThief.isUpdateOption()) {
                ThiefBusiness.updateUserThief(userThief);
            }
        }
        return true;
    }

    @Override
    public void afterLogin() {

        // 系统开关判断
        if (SystemSwitchMgr.getLockSystemIdList().contains(eSystemId.ThiefSystem.getValue())) {
            // 系统开关关了把已有小偷都清空
            for (UserThief userThief : thiefMap.values()) {
                if (ThiefMgr.getThiefStatus(userThief) != eThiefStatus.HadGetReward) {
                    log.info("ThiefModule delete thief! userId={},thiefUid={},thiefType={}", getUserId(), userThief.getThiefUid(), userThief.getType());
                    userThief.setGetReward(true);
                }
            }
            return;
        }

        if (!SystemOpenMgr.systemOpen(player, eSystemId.ThiefSystem.getValue())) {
            return;
        }

        if (ThiefMgr.isPlayerHadGuide(player)) {
            // 刷新数据
            checkCreateThief();
            // 同步全部数据
            List<UserThief> list = new ArrayList<>();
            for (UserThief thief : thiefMap.values()) {
                if (ThiefMgr.getThiefStatus(thief) != eThiefStatus.HadGetReward) {
                    list.add(thief);
                }
            }
            if (!list.isEmpty()) {
                syncThief(list, 1);
            }
        } else {
            // 未过引导，同步引导数据
            syncCanCreateGuide();
        }
    }

    /**
     * 生成小偷
     */
    public synchronized List<UserThief> checkCreateThief() {
        synchronized (createLock) {

            // 系统开关判断
            if (SystemSwitchMgr.getLockSystemIdList().contains(eSystemId.ThiefSystem.getValue())) {
                return new ArrayList<>();
            }

            // 系统解锁判断
            if (!SystemOpenMgr.systemOpen(player, eSystemId.ThiefSystem.getValue())) {
                return new ArrayList<>();
            }

            // 是否过引导判断
            if (!ThiefMgr.isPlayerHadGuide(player)) {
                return new ArrayList<>();
            }

            long now = System.currentTimeMillis();

            // 计算生成时间
            List<Long> createTimeList = getCreateTimeList();

            // 修改时间
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.ThiefLastCheckTime, now);

            if (createTimeList.size() == 0) {
                return new ArrayList<>();
            }

            // 生成小偷
            Random random = new Random();
            List<UserThief> toSyncList = new ArrayList<>();
            for (Long createTime : createTimeList) {

                List<Integer> createData = getRandomCreateThiefData(random);
                int thiefType = createData.get(0);
                int placeId = createData.get(1);

                if (thiefType == -1 || placeId == -1) {
                    break;
                }

                toSyncList.add(
                        // 生成小偷
                        createOneThief(thiefType, placeId, createTime)
                );
            }

            return toSyncList;
        }
    }

    /**
     * 生成一个小偷
     *
     * @param type         小偷类型
     * @param crimePlaceId 小偷作案地点
     * @param createTime   生成时间
     */
    private UserThief createOneThief(int type, int crimePlaceId, long createTime) {
        UserThief userThief = new UserThief();
        userThief.setUserId(player.getUserId());
        userThief.setThiefUid(UUIDHelper.randomUUID(String.valueOf(GameServer.getInstance().getServerId())));
        userThief.setType(type);
        userThief.setCrimePlaceId(crimePlaceId);
        userThief.setCreateTime(0L);
        userThief.setCreateTime(createTime);
        userThief.setGetReward(false);
        userThief.setInsertOption();

        thiefMap.put(userThief.getThiefUid(), userThief);

        return userThief;
    }

    /**
     * 获取空犯罪地点
     */
    private List<Integer> getEmptyCrimePlaceList() {
        List<Integer> crimePlaceIdList = new ArrayList<>(StringUtils.stringToIntegerList(GameConfig.THIEF_CRIME_PLACE_ID_LIST, ";"));
        for (UserThief userThief : thiefMap.values()) {
            if (ThiefMgr.getThiefStatus(userThief) == eThiefStatus.NoCatch) {
                crimePlaceIdList.remove(Integer.valueOf(userThief.getCrimePlaceId()));
            }
        }
        return crimePlaceIdList;
    }

    /**
     * 获取生成时间
     */
    private List<Long> getCreateTimeList() {

        List<Long> createTimeList = new ArrayList<>();

        int noCatchCount = 0;
        int workingCount = 0;
        int workingFinishCount = 0;
        for (UserThief userThief : thiefMap.values()) {
            eThiefStatus status = ThiefMgr.getThiefStatus(userThief);
            if (status == eThiefStatus.NoCatch) noCatchCount++;
            else if (status == eThiefStatus.Working) workingCount++;
            else if (status == eThiefStatus.WorkingFinish) workingFinishCount++;
        }

        int condition1 = GameConfig.THIEF_MAX_NO_CATCH_COUNT - noCatchCount;
        int condition2 = GameConfig.THIEF_MAX_ON_MAP_COUNT - noCatchCount - workingCount - workingFinishCount;

        int count = condition1 <= condition2 ? condition1 : condition2;
        if (count <= 0) return createTimeList;

        long lastCheckTime = player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.ThiefLastCheckTime);
        long now = System.currentTimeMillis();
        long zeroTime = LocalDateTimeHelper.getZeroTimeTimeStamp(lastCheckTime);
        long tmpCreateTime;
        boolean end = false;
        List<Long> refreshTimeList = StringUtils.stringToLongList(GameConfig.THIEF_REFRESH_TIME_LIST, ";"); // 分钟

        for (int i = 0; i < 100; i++) { // 一天天遍历，直到无法再生成
            zeroTime = zeroTime + i * 24L * 60L * 60L * 1000L;
            for (Long refreshTime : refreshTimeList) { // 遍历生成时间点
                tmpCreateTime = zeroTime + refreshTime * 60L * 1000L;
                if (tmpCreateTime > now
                        || createTimeList.size() >= count) { // 时间超过现在 || 已生成数量达到上限
                    end = true;
                    break;
                }
                if (tmpCreateTime < lastCheckTime) {
                    continue;
                }
                createTimeList.add(tmpCreateTime);
            }
            if (end) {
                break;
            }
        }
        return createTimeList;
    }

    /**
     * 抓小偷
     */
    public int catchThief(String thiefUid) {
        UserThief userThief = thiefMap.get(thiefUid);
        if (userThief == null) {
            return GameErrorCode.E_THIEF_NO_EXIST;
        }
        if (ThiefMgr.getThiefStatus(userThief) != eThiefStatus.NoCatch) {
            return GameErrorCode.E_THIEF_HAD_CATCH;
        }

        // 判断该店铺正在打工的数据（每个店铺只会有一种小偷）
        for (UserThief thief : thiefMap.values()) {
            if (thief.getType() == userThief.getType()) {
                eThiefStatus thiefStatus = ThiefMgr.getThiefStatus(thief);
                if (thiefStatus == eThiefStatus.Working || thiefStatus == eThiefStatus.WorkingFinish) {
                    return GameErrorCode.E_THIEF_WORK_SHOP_LIMIT;
                }
            }
        }

        // 抓捕后改为打工状态
        userThief.setWorkBeginTime(System.currentTimeMillis());

        // 同步数据
        List<UserThief> list = new ArrayList<>();
        list.add(userThief);
        syncThief(list, 2);
        player.getModule(AttributeModule.class).addAttribute(ePlayerAttrType.CatchThiefCount,1);
        player.notifyListener(eGamePlayerEventType.CatchThiefCount.getValue(), player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.CatchThiefCount));
        // 返回
        ThiefProto.CatchThiefRespMsg.Builder builder = ThiefProto.CatchThiefRespMsg.newBuilder();
        builder.setRet(0);
        builder.setWorkBeginTime(userThief.getWorkBeginTime());
        player.sendPacket(ClientProtocol.U_THIEF_CATCH, builder);

        return 0;
    }

    /**
     * 同步小偷
     *
     * @param type 1全量，2增量
     */
    public void syncThief(List<UserThief> thiefList, int type) {
        ThiefProto.SyncUserThiefRespMsg.Builder builder = ThiefProto.SyncUserThiefRespMsg.newBuilder();
        for (UserThief userThief : thiefList) {
            builder.addThiefMsgList(ThiefPb.parseUserThiefMsg(userThief));
        }
        builder.setType(type);
        player.sendPacket(ClientProtocol.U_THIEF_SYNC_THIEF, builder);
    }

    /**
     * 领小偷打工奖励
     */
    public void getThiefWorkReward(String thiefUid) {
        int ret = 0;

        UserThief userThief = thiefMap.get(thiefUid);
        ThiefInfo thiefInfo = null;
        if (userThief != null) {
            thiefInfo = ThiefMgr.getThiefInfo(userThief.getType());
        }

        if (userThief == null || thiefInfo == null) {
            ret = GameErrorCode.E_THIEF_NO_EXIST;
        } else {
            eThiefStatus thiefStatus = ThiefMgr.getThiefStatus(userThief);
            if (thiefStatus == eThiefStatus.HadGetReward) {
                ret = GameErrorCode.E_THIEF_HAD_GET_REWARD;
            } else if (ThiefMgr.getThiefStatus(userThief) != eThiefStatus.WorkingFinish) {
                ret = GameErrorCode.E_THIEF_WORK_NO_FINISH;
            } else {

                // 改状态
                userThief.setGetReward(true);
                // 领奖
                Property reward = PropertyHelper.parseStringToProperty(thiefInfo.getReward());
                player.getModule(CurrencyModule.class).addCurrency(reward, eLogMoneyType.Thief, eLogMoneyType.ThiefWorkReward);

                // 日志
                LogMgr.addLogThiefReward(new LogThiefReward(getUserId(), thiefInfo.getType(), userThief.getThiefUid(), thiefInfo.getReward()));

                // 同步
                List<UserThief> list = new ArrayList<>();
                list.add(userThief);
                syncThief(list, 2);
            }
        }

        ThiefProto.GetThiefWorkRewardRespMsg.Builder builder = ThiefProto.GetThiefWorkRewardRespMsg.newBuilder();
        builder.setRet(ret);
        if (ret == 0) {
            builder.setReward(thiefInfo.getReward());
        }
        player.sendPacket(ClientProtocol.U_THIEF_GET_REWARD, builder);
    }

    /**
     * 生成引导小偷
     */
    public int createGuideThief() {

        synchronized (createLock) {

            if (!SystemOpenMgr.systemOpen(player, eSystemId.ThiefSystem.getValue())) {
                return GameErrorCode.E_THIEF_NO_UNLOCK;
            }

            if (ThiefMgr.isPlayerHadGuide(player)) {
                return GameErrorCode.E_THIEF_HAD_CREATE_GUIDE;
            }

            // 获取小偷引导配置
            List<Integer> guideList = StringUtils.stringToIntegerList(GameConfig.THIEF_GUIDE_PARAM, ";");
            int thiefType = guideList.get(0);
            int crimePlace = guideList.get(1);

            // 配置校验
            if (ThiefMgr.getThiefInfo(thiefType) == null) {
                log.error("ThiefModule createGuideThief error! Can not find thiefInfo! GameConfig.THIEF_GUIDE_PARAM={}", GameConfig.THIEF_GUIDE_PARAM);
                return GameErrorCode.E_THIEF_NO_EXIST;
            }
            List<Integer> placeIdList = StringUtils.stringToIntegerList(GameConfig.THIEF_CRIME_PLACE_ID_LIST, ";");
            List<Integer> collect = placeIdList.stream().filter(item -> item == crimePlace).collect(Collectors.toList());
            if (collect.size() == 0) {
                log.error("ThiefModule createGuideThief error! Can not find crimePlaceId! GameConfig.THIEF_GUIDE_PARAM={}, public static String THIEF_CRIME_PLACE_ID_LIST;={}",
                        GameConfig.THIEF_GUIDE_PARAM, GameConfig.THIEF_CRIME_PLACE_ID_LIST);
                return GameErrorCode.E_THIEF_NO_EXIST;
            }

            // 生成引导小偷
            UserThief userThief = createOneThief(thiefType, crimePlace, System.currentTimeMillis());
            // 引导小偷直接开始打工
            userThief.setWorkBeginTime(System.currentTimeMillis());

            // 修改时间
            player.getModule(AttributeModule.class).setAttribute(ePlayerAttrType.ThiefLastCheckTime, System.currentTimeMillis());
            player.getModule(AttributeModule.class).addAttribute(ePlayerAttrType.CatchThiefCount,1);
            player.notifyListener(eGamePlayerEventType.CatchThiefCount.getValue(), player.getModule(AttributeModule.class).getAttribute(ePlayerAttrType.CatchThiefCount));

            ThiefProto.CreateGuideThiefRespMsg.Builder builder = ThiefProto.CreateGuideThiefRespMsg.newBuilder();
            builder.setRet(0);
            builder.setThiefMsg(ThiefPb.parseUserThiefMsg(userThief));
            player.sendPacket(ClientProtocol.U_THIEF_CREATE_GUIDE, builder);

            return 0;
        }
    }

    /**
     * 同步可生成引导
     */
    public void syncCanCreateGuide() {
        ThiefProto.SyncCreateGuideThiefRespMsg.Builder builder = ThiefProto.SyncCreateGuideThiefRespMsg.newBuilder();
        player.sendPacket(ClientProtocol.U_THIEF_SYNC_GUIDE, builder);
    }

    /**
     * 随机可用的新小偷数据
     *
     * @return List，0：小偷类型，1作案地点
     */
    public List<Integer> getRandomCreateThiefData(Random random) {
        List<Integer> result = new ArrayList<>();
        result.add(-1);
        result.add(-1);

        // 获取已有类型
        Set<Integer> existTypeSet = new HashSet<>();
        for (UserThief userThief : thiefMap.values()) {
            eThiefStatus thiefStatus = ThiefMgr.getThiefStatus(userThief);
            if (thiefStatus == eThiefStatus.NoCatch || thiefStatus == eThiefStatus.Working || thiefStatus == eThiefStatus.WorkingFinish) {
                existTypeSet.add(userThief.getType());
            }
        }
        // 获取所有小偷类型和权重
        List<Integer> typeList = new ArrayList<>();
        List<Integer> weightList = new ArrayList<>();
        for (ThiefInfo thiefInfo : ThiefMgr.getThiefInfoMap().values()) {
            UserBuilding building = player.getModule(BuildingModule.class).getBuildingById(thiefInfo.getUnlockBuildingId());
            if (building != null) {
                typeList.add(thiefInfo.getType());
                weightList.add(thiefInfo.getWeight());
            }
        }
        if (typeList.size() == 0) return result;

        // 过滤已有类型
        boolean canRandom = false;
        if (existTypeSet.size() < typeList.size()) {
            for (int i = 0; i < typeList.size(); i++) {
                if (existTypeSet.contains(typeList.get(i))) {
                    weightList.set(i, 0);
                } else {
                    canRandom = true;
                }
            }
        }
        if (!canRandom) return result;

        // 过滤没有生成地点的小偷
        canRandom = false;
        List<Integer> emptyPlaceList = getEmptyCrimePlaceList();
        for (Integer type : typeList) {
            boolean canCreate = false;
            ThiefInfo thiefInfo = ThiefMgr.getThiefInfo(type);
            for (Integer placeId : thiefInfo.getPlaceIdList()) {
                if (emptyPlaceList.contains(placeId)) {
                    canCreate = true;
                    break;
                }
            }
            if (!canCreate) {
                int index = typeList.indexOf(type);
                weightList.set(index, 0);
            } else {
                canRandom = true;
            }
        }
        if (!canRandom) return result;

        // 随机小偷类型
        ThiefInfo thiefInfo = ThiefMgr.getThiefInfo(typeList.get(RandomHelper.getRandomIndexByWeight(weightList, random)));

        // 随机地点
        List<Integer> placeList = new ArrayList<>();
        for (Integer placeId : thiefInfo.getPlaceIdList()) {
            if (emptyPlaceList.contains(placeId)) {
                placeList.add(placeId);
            }
        }
        Integer placeId = placeList.get(random.nextInt(placeList.size()));

        // 设置结果
        result.set(0, thiefInfo.getType());
        result.set(1, placeId);

        return result;
    }
}
